/**
 * MITM Server Admin Thread
 */

package mitm;

import java.net.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;

// You need to add code to do the following
// 1) use SSL sockets instead of the plain sockets provided
// 2) check user authentication
// 3) perform the given administration command

class MITMAdminServer implements Runnable {
    private ServerSocket m_serverSocket;
    private Socket m_socket = null;
    private HTTPSProxyEngine m_engine;
    private StatsRecorder sr;
    private HashMap<String,String> users;
    
    public MITMAdminServer( String localHost, int adminPort, HTTPSProxyEngine engine, String passwdFile ) throws IOException,java.security.GeneralSecurityException {
	MITMSSLSocketFactory socketFactory =
	    new MITMSSLSocketFactory();
	m_serverSocket = socketFactory.createServerSocket( localHost, adminPort, 0 );
	m_engine = engine;
	sr = StatsRecorder.getStatsRecorder();
	users = MITMPassword.getPasswords( passwdFile );
	System.out.println("Read in " + users.size() + " user accounts" );
    }
    
    public void run() {
	System.out.println("Admin server initialized, listening on port " + m_serverSocket.getLocalPort());
	while( true ) {
	    try {
		m_socket = m_serverSocket.accept();
		
		byte[] buffer = new byte[40960];
		
		Pattern userPwdPattern =
		    Pattern.compile("username:(\\S+)\\s+password:(\\S+)\\s+command:(\\S+)\\sCN:(\\S*)\\s");
		
		BufferedInputStream in =
		    new BufferedInputStream(m_socket.getInputStream(),
					    buffer.length);
		
		// Read a buffer full.
		int bytesRead = in.read(buffer);
		
		String line =
		    bytesRead > 0 ?
		    new String(buffer, 0, bytesRead) : "";
		
		Matcher userPwdMatcher =
		    userPwdPattern.matcher(line);
		
		// parse username and pwd
		if (userPwdMatcher.find()) {
		    String userName = userPwdMatcher.group(1);
		    String password = userPwdMatcher.group(2);
		    
		    // if authentication fails, I just close the socket

		    if ( !users.containsKey(userName) ) {
			//User does not exist in the password DB, reject
			System.out.println( "Unknown user: " + userName );
		    } else if ( !users.get(userName).equals(password) ) {
			//password doesn't matching, reject
			System.out.println( "Invalid password: " + password );

		    } else {
			// if authenticated, do the command
			boolean authenticated = true;
			if( authenticated ) {
			    String command = userPwdMatcher.group(3);
			    String commonName = userPwdMatcher.group(4);
			    
			    doCommand( command );
			}
		    }

		    // We are done, close the socket
		    m_socket.close();
		}	
	    }
	    catch( InterruptedIOException e ) {
	    }
	    catch( Exception e ) {
		e.printStackTrace();
	    }
	}
    }

    private void doCommand( String cmd ) throws IOException {

	System.out.println( "Admin Command Received: " + cmd );

	if ( cmd.equals( "shutdown" ) ) {
	    System.exit(0);
	} else if ( cmd.equals( "stats" ) ) {
	    System.out.println( "The total count of proxied requests is: " + sr.getCount() );
	    
	    PrintWriter out =
		new PrintWriter( new BufferedOutputStream( m_socket.getOutputStream() ) );
	    out.println( "Proxied Requests = " + sr.getCount() );
	    out.close();
	}
	
    }


} /*MITMAdminServer*/
